package cn.ibizlab.businesscentral.core.util.aspect;

import cn.ibizlab.businesscentral.core.odoo_ir.domain.Ir_model_fields;
import cn.ibizlab.businesscentral.core.odoo_ir.domain.Ir_property;
import cn.ibizlab.businesscentral.core.odoo_ir.filter.Ir_propertySearchContext;
import cn.ibizlab.businesscentral.core.odoo_ir.service.IIr_model_fieldsService;
import cn.ibizlab.businesscentral.core.odoo_ir.service.IIr_propertyService;
import cn.ibizlab.businesscentral.core.util.helper.EBSServiceImpl;
import cn.ibizlab.businesscentral.util.annotation.BackFillProperty;
import cn.ibizlab.businesscentral.util.annotation.DynaProperty;
import cn.ibizlab.businesscentral.util.domain.EntityBase;
import cn.ibizlab.businesscentral.util.domain.EntityMP;
import cn.ibizlab.businesscentral.util.helper.CaseFormatMethod;
import cn.ibizlab.businesscentral.util.helper.DEFieldCacheMap;
import cn.ibizlab.businesscentral.util.security.SpringContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.NumberUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 回填属性切面
 */
@Aspect
@Component
@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
public class BackFillPropertyAspect {
    private final ExpressionParser parser = new SpelExpressionParser();

    @Before(value = "execution(* cn.ibizlab.businesscentral.core.*.service.*.*.create(..)) && args(entity,..) ")
    public void create(EntityMP entity) throws Throwable {
        Map<String, Object> refEntityMap = new HashMap<>();
        Map<String, Object> refEntityServiceMap = new HashMap<>();
        Map<String, BackFillProperty> backFillPropertyFields = DEFieldCacheMap.getBackFillropertyFields(entity.getClass());
        if (backFillPropertyFields.size() == 0)
            return;
        for (Map.Entry<String, BackFillProperty> entry : backFillPropertyFields.entrySet()) {
            Field field = DEFieldCacheMap.getField(entity.getClass(), entry.getKey());
            BackFillProperty backFillProperty = entry.getValue();
            String fieldProperty = CaseFormatMethod.exec(field.getName(), "lC2l_u");
            if (entity.get(backFillProperty.referenceName()) == null)
                continue;
            Object refEntity = null;
            if (!refEntityMap.containsKey(backFillProperty.referenceKey())) {
                refEntity = backFillProperty.reference().newInstance();
                setRefEntityValue(refEntity, backFillProperty.referenceKey(), entity.get(backFillProperty.referenceName()));
                refEntityMap.put(backFillProperty.referenceKey(), refEntity);
                refEntityServiceMap.put(backFillProperty.referenceKey(), SpringContextHolder.getBean(backFillProperty.referenceService()));
            }
            refEntity = refEntityMap.get(backFillProperty.referenceKey());
            if (entity.getFocusNull().contains(fieldProperty) || entity.get(fieldProperty) != null)
                setRefEntityValue(refEntity, backFillProperty.backFillName(), entity.get(fieldProperty));
        }

        //refEntity 更新处理
        for (Map.Entry<String, Object> entry : refEntityMap.entrySet()) {
            updateRefEntity(refEntityServiceMap.get(entry.getKey()), entry.getValue());
        }

        return;
    }

    @Before("execution(* cn.ibizlab.businesscentral.core.*.service.*.*.update(..)) && args(entity,..)")
    public void update(EntityMP entity) throws Throwable {
        Map<String, Object> refEntityMap = new HashMap<>();
        Map<String, Object> refEntityServiceMap = new HashMap<>();
        Map<String, BackFillProperty> backFillPropertyFields = DEFieldCacheMap.getBackFillropertyFields(entity.getClass());
        if (backFillPropertyFields.size() == 0)
            return;
        for (Map.Entry<String, BackFillProperty> entry : backFillPropertyFields.entrySet()) {
            Field field = DEFieldCacheMap.getField(entity.getClass(), entry.getKey());
            BackFillProperty backFillProperty = entry.getValue();
            String fieldProperty = CaseFormatMethod.exec(field.getName(), "lC2l_u");
            if (entity.get(backFillProperty.referenceName()) == null)
                continue;
            Object refEntity = null;
            if (!refEntityMap.containsKey(backFillProperty.referenceKey())) {
                refEntity = backFillProperty.reference().newInstance();
                setRefEntityValue(refEntity, backFillProperty.referenceKey(), entity.get(backFillProperty.referenceName()));
                refEntityMap.put(backFillProperty.referenceKey(), refEntity);
                refEntityServiceMap.put(backFillProperty.referenceKey(), SpringContextHolder.getBean(backFillProperty.referenceService()));
            }
            refEntity = refEntityMap.get(backFillProperty.referenceKey());
            if (entity.getFocusNull().contains(fieldProperty) || entity.get(fieldProperty) != null)
                setRefEntityValue(refEntity, backFillProperty.backFillName(), entity.get(fieldProperty));
        }

        //refEntity 更新处理
        for (Map.Entry<String, Object> entry : refEntityMap.entrySet()) {
            updateRefEntity(refEntityServiceMap.get(entry.getKey()), entry.getValue());
        }

        return;
    }

    private void setRefEntityValue(Object refEntity, String property, Object value) throws Exception {
        refEntity.getClass().getMethod("set", String.class, Object.class).invoke(refEntity, property, value);
    }

    private void updateRefEntity(Object refEntityService, Object refEntity) throws Exception {
        refEntityService.getClass().getMethod("update", refEntity.getClass()).invoke(refEntityService, refEntity);
    }

}